Residencia de Epidemiología
“Un simple gráfico ha brindado más información a la mente del analista de datos que cualquier otro dispositivo”. — John Tukey
De manera similar a la gramática lingüística, “La gramática de gráficos” define un conjunto de reglas para construir gráficos estadísticos combinando diferentes tipos de capas.
Esta gramática fue creada por Leland Wilkinson (2005, The Grammar of Graphics (Statistics and Computing). Secaucus, NJ, USA: Springer-Verlag New York, Inc.)
ggplot2 es un paquete que se autodefine como librería para “crear elegantes visualizaciones de datos usando una gramática de gráficos”
El paquete propone un sistema que se basa en la idea que cualquier gráfico se puede construir usando tres componentes básicos:
Datos con estructura “ordenada”
Mapeo estético (aesthetic) de los datos
Objetos geométricos que dan nombre al tipo de gráfico
Coordenadas que organizan los objetos geométricos
Escalas (scale) definen el rango de valores de las estéticas
Facetas que agrupan en subgráficos
Las capas posteriores son opcionales. Algunas de ellas son:
La idea en esta presentación es mostrar paso a paso la construcción de un gráfico.
Partiremos del objetivo deseado, en este caso un tipo de gráfico que ya existe, pero podría ser algún otro ejemplo o un bosquejo de lo imaginado garabateado en un papel.
El segundo paso es determinar cuales son las variables necesarias para construir ese gráfico y donde se mapean.
El tercer paso es trabajar con los datos y transformarlos para que estén preparados para graficar.
El cuarto es el gráfico en si mismo con todas las personalizaciones de sus partes.
Queremos construir un gráfico similar a este
El análisis del modelo indica que hay dos capas geométricas simultáneas: una de barras y otra de líneas.
También hay dos ejes y (a izquierda Números de casos y a derecha Tasas por 100.000) y un eje x (Años)
Las variables participantes son tres:
y1,y2 yx.Importamos datos de la tendencia de TB de la provincia de Santa Fe entre los años 1980 y 2008
library(tidyverse)
library(readxl)
tendencia1 <- read_excel("datos/Tendencia tb 1980 2008 por provincia.xls",
sheet = "SFE", range = "A6:A34", col_names = F) |>
rename("Año" = ...1)
tendencia2 <- read_excel("datos/Tendencia tb 1980 2008 por provincia.xls",
sheet = "SFE", range = "D6:E34", col_names = F) |>
rename("Casos" = ...1,
"Tasa" = ...2)
tendencia <- tendencia1 |>
bind_cols(tendencia2) El dataframe necesario para este gráfico nos quedaría así:
# A tibble: 29 × 3
Año Casos Tasa
<dbl> <dbl> <dbl>
1 1980 904 36.2
2 1981 790 31.2
3 1982 853 33.3
4 1983 802 30.9
5 1984 794 30.2
6 1985 669 25.1
7 1986 659 24.5
8 1987 516 18.9
9 1988 722 26.2
10 1989 661 23.7
# ℹ 19 more rows
Iniciamos con el gráfico de barras. Mapeamos x e y, indicamos color de relleno e identidad porque las barras se van a construir con el conteo previo (datos agregados)
Agregamos capa de texto con los valores de los casos.
Adecuamos los valores en las barras.
Configuramos eje x
Personalizamos mejor el eje x (ángulo de las etiquetas, etc)
tendencia |>
ggplot(aes(x = Año, y = Casos, label = Casos)) +
geom_bar(stat = "identity",
fill = "royalblue") +
geom_text(hjust = 1.2, vjust = 0.5, angle = 90, color = "white") +
scale_x_continuous(name = "Años", breaks = seq(1980, 2008, 1)) +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 11))Configuramos el eje y asociado a las barras
tendencia |>
ggplot(aes(x = Año, y = Casos, label = Casos)) +
geom_bar(stat = "identity",
fill = "royalblue") +
geom_text(hjust = 1.2, vjust = 0.5, angle = 90, color = "white") +
scale_x_continuous(name = "Años", breaks = seq(1980, 2008, 1)) +
scale_y_continuous(name = "Número de casos", breaks = seq(0, 1000, 200)) +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 11),
axis.text.y = element_text(size = 11))Incoporamos el segundo gráfico o segunda capa geométrica. Utilizamos una constante para llevar los valores al mismo orden de los valores de las barras.
tendencia |>
ggplot(aes(x = Año, y = Casos, label = Casos)) +
geom_bar(stat = "identity",
fill = "royalblue") +
geom_line(aes(y = Tasa*35), color = "red", linewidth = 1.5) +
geom_text(hjust = 1.2, vjust = 0.5, angle = 90, color = "white") +
scale_x_continuous(name = "Años",
breaks = seq(1980, 2008, 1)) +
scale_y_continuous(name = "Número de casos",
breaks = seq(0, 1000, 200),
sec.axis = sec_axis(~./35,
name = "Tasa")) +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 11),
axis.text.y = element_text(size = 11))Agregamos etiquetas asociadas a la capa geométrica line
tendencia |>
ggplot(aes(x = Año, y = Casos, label = Casos)) +
geom_bar(stat = "identity",
fill = "royalblue") +
geom_line(aes(y = Tasa*35), color = "red", linewidth = 1.5) +
geom_text(hjust = 1.2, vjust = 0.5, angle = 90, color = "white") +
geom_text(aes(label = round(Tasa,1), y = Tasa*35), angle = 45, hjust = -0.2, vjust = -0.5) +
scale_x_continuous(name = "Años",
breaks = seq(1980, 2008, 1)) +
scale_y_continuous(name = "Número de casos",
breaks = seq(0, 1400, 200),
limits = c(0,1400),
sec.axis = sec_axis(~./35,
name = "Tasas por 100.000",
breaks = seq(0, 60, 10))) +
theme(axis.text.x = element_text(angle = 45,
hjust = 1,
size = 11),
axis.text.y = element_text(size = 11))Al igual que el modelo del gráfico, sumamos dentro del mismo las leyendas
tendencia |>
ggplot(aes(x = Año, y = Casos, label = Casos, fill = "Número de casos")) +
geom_bar(stat = "identity") +
geom_line(aes(y = Tasa*35, color = "Tasas por 100.000"), linewidth = 1.5) +
geom_text(hjust = 1.2, vjust = 0.5, angle = 90, color = "white") +
geom_text(aes(label = round(Tasa,1), y = Tasa*35), angle = 45, hjust = -0.2, vjust = -0.5) +
scale_x_continuous(name = "Años",
breaks = seq(1980, 2008, 1)) +
scale_y_continuous(name = "Número de casos",
breaks = seq(0, 1400, 200),
limits = c(0,1400),
sec.axis = sec_axis(~./35,
name = "Tasas por 100.000",
breaks = seq(0, 60, 10))) +
scale_fill_manual(values = "royalblue") +
scale_color_manual(values = "red") +
theme(axis.text.x = element_text(angle = 45,
hjust = 1,
size = 11),
axis.text.y = element_text(size = 11),
legend.position = "inside",
legend.position.inside = c(0.8, 0.8),
legend.background = element_rect(fill = "transparent"),
legend.text.position = "right",
legend.title=element_blank()) +
guides(color = guide_legend(order = 0),
fill = guide_legend(order = 1))Por último, definimos estructura de titulo, subtitulo y pie de gráfico (habría que reemplazarlos por la definición de cada uno).
tendencia |>
ggplot(aes(x = Año, y = Casos, label = Casos, fill = "Número de casos")) +
geom_bar(stat = "identity") +
geom_line(aes(y = Tasa*35, color = "Tasas por 100.000"), linewidth = 1.5) +
geom_text(hjust = 1.2, vjust = 0.5, angle = 90, color = "white") +
geom_text(aes(label = round(Tasa,1), y = Tasa*35), angle = 45, hjust = -0.2, vjust = -0.5) +
scale_x_continuous(name = "Años",
breaks = seq(1980, 2008, 1)) +
scale_y_continuous(name = "Número de casos",
breaks = seq(0, 1400, 200),
limits = c(0,1400),
sec.axis = sec_axis(~./35,
name = "Tasas por 100.000",
breaks = seq(0, 60, 10))) +
scale_fill_manual(values = "royalblue") +
scale_color_manual(values = "red") +
labs(title = "Titulo", subtitle = "subtitulo", caption = "pie de grafico" ) +
theme(axis.text.x = element_text(angle = 45,
hjust = 1,
size = 11),
axis.text.y = element_text(size = 11),
legend.position = "inside",
legend.position.inside = c(0.8, 0.8),
legend.background = element_rect(fill = "transparent"),
legend.text.position = "right",
legend.title=element_blank()) +
guides(color = guide_legend(order = 0),
fill = guide_legend(order = 1))Desde el panel Plot de RStudio
En formatos conocidos como JPG, PNG, PDF, etc
Mayor control con la función ggsave()
ggsave(filename, # nombre del archivo
plot = last_plot(), # nombre del objeto gráfico
device = NULL, # formato de salida "jpeg", "png", "tiff", "pdf", etc
width = NA, # ancho en unidades de units
height = NA, # alto en unidades de units
units = c("in", "cm", "mm"), # unidades de medidas
dpi = 300) # resolución de salida en dpiMuchas veces nos encontramos con la situación de crear un gráfico que se ve bien en el panel Plot de RStudio y cuando lo exportamos o incluímos dentro de un documento de Quarto el tamaño de sus partes (elementos geométricos, textos, leyendas, etc) se achican o agrandan de tal forma que el producto final es feo y/o desproporcionado.
La respuesta a estos problemas tienen que ver con dos conceptos que debemos entender y poder controlar: el tamaño y la resolución.
Repasemos algunos conceptos de la imagen en pantalla:
Hagamos algunos calculos para ver si todo está en orden:
ancho: 1920 (px) / 96 (px/in) = 20 pulgadas
alto: 1200 (px) / 96 (px/in) = 12,5 pulgadas
relación: 1920 / 1200 = 20 / 12,5 = 16/10
Las imágenes que se crean con ggplot2, por ejemplo, están constituidas por pixeles.
En estas imágenes también se relacionan las dimensiones y las resoluciones.
Para pasar de la dimensión en pulgadas a una cantidad de puntos, por ejemplo al exportar con ggsave() se utiliza la cantidad de puntos por pulgadas (dpi).
Si creamos un gráfico de 12 x 10 pulgadas a 300 dpi, el archivo será una matriz de (12 * 300) x (10 * 300) = 3600 x 3000 puntos.
Cuando abrimos el archivo en nuestra computadora, cada punto representa un pixel, lo que da una imagen de 3600 x 3000 px de resolución.
Imaginemos que tenemos una imagen de 500x500px. Así se vería cada una, con un zoom del 100%, en un monitor de 1080p (1920x1080px) y en otro 4K (3840×2160), ambos del mismo tamaño.
Hagamos un pequeño experimento con un gráfico sencillo basado en los pinguinos.
Si calculamos, la salida se almacena como:
ancho: 10 pulgadas * 300 dpi = 3000 px
alto: 5 pulgadas * 300 dpi = 1500 px
Ahora si en lugar de guardar el gráfico solo lo visualizaramos en el monitor:
ancho: 10 pulgadas * 96 dpi = 960 px
alto: 5 pulgadas * 96 dpi = 480 px
Si visualizamos un gráfico con muchos más pixeles que otro en el mismo espacio (nuestra pantalla) los elementos que lo componen se van a ver siempre más pequeños.
Importa porque algunos elementos del gráfico se ajustan al espacio disponible, y algunos son fijos y medidos en su dimensión real (cm, mm o pulgadas) como las fuentes de los textos, creando una distorsión al cambiar la dimensión del gráfico o su resolución.
| Formato | Por defecto |
|---|---|
| Por defecto | 7 x 5 |
| Diapositivas HTML | 9,5 x 6,5 |
| Diapositivas HTML (reveal.js) | 9 x 5 |
| 5,5 x 3,5 | |
| Diapositivas PDF (Beamer) | 10x7 |
| PowerPoint | 7,5 x 5,5 |
| MS Word, ODT, RTF | 5x4 |
| EPUB | 5x4 |
* Medidas en pulgadas
Comparemos dos archivos exportados desde ggplot2:
font_prueba1_5x5_300.png
font_prueba1_10x10_300.png
Observamos que el tamaño del punto y la fuente parecen más pequeños en el gráfico de la derecha.
De hecho no son más pequeños, siguen teniendo el mismo tamaño en pulgadas, y como guardamos con la misma resolución (dpi = 300), tienen el mismo número de puntos (tamaño en pulgadas * 300).
La fuente del gráfico aparece más pequeña porque el segundo gráfico es más grande (3000x3000 frente a 1500x1500) y se reduce su aspecto para que el gráfico entre el espacio de la pantalla.
Además tenemos otro problema. De forma predeterminada, el tamaño de las fuentes de la configuración de theme() está definido en pts. (15 significa 15 puntos - pts-).
En cambio, en la capa geom_text(), el tamaño se define en mm, por lo que 15 es 15 mm.
1 punto = 1/72 pulgadas
1 punto = 0,35 mm
Entonces si queremos que el texto tenga el mismo tamaño que el título, el tamaño en mm será 15 pt * 0,35 pt/mm = 5,25 mm
En ggplot, hay una constante definida para realizar la conversión, .pt = 2,845276. (1/.pt = 0,35). Podemos escribir .pt en la consola y mostrará su valor:
Entonces para hacer la conversión:
de pt a mm : mm = pt / .pt -> 15 / 2,845276 = 5,27 mm
de mm a pt : pt = mm * .pt -> 5,27 * 2,845276 = 15 pts
Instituto Nacional de Epidemiología